# Polling
# Polling (от англ. "опрос") — это метод мониторинга состояния какого-либо устройства, системы или процесса.
# Он основывается на периодическом опрашивании устройства для получения информации о его состоянии. Polling может 
# использоваться для отслеживания состояния ввода, например, состояния клавиатуры или мыши, или для определения состояния сетевых
# устройств, таких как принтеры или серверы.

# Однако Polling может быть медленным и ресурсоемким, поскольку процесс мониторинга выполняется постоянно. Для улучшения эффективности
# используются другие методы, такие как прерывания (Interrupts).

# Недостатки polling: 

# Polling требует постоянного мониторинга, что может привести к высокой нагрузке на процессор и память.

# Polling может быть медленным, поскольку он должен постоянно опрашивать устройство или систему, чтобы получить информацию о ее состоянии.

# Polling может быть неэффективным, поскольку он требует постоянного мониторинга, даже если устройство или система не имеют никаких изменений.

# Из-за этих недостатков в некоторых случаях лучше использовать прерывания (*Interrupts) вместо поллинга, чтобы улучшить эффективность и
# уменьшить нагрузку на процессор.

# *Interrupts (прерывания) - это механизм, который позволяет процессору прерывать текущую задачу и переключаться на выполнение другой задачи,
# когда происходит определенное событие, такое как нажатие клавиши или получение данных от устройства. Прерывания не нуждаются в постоянном 
# мониторинге устройств или событий. Вместо этого процесс может продолжать выполнение текущей задачи, а когда происходит событие, он 
# прерывается и выполняет соответствующую задачу.

# Пример кода, демонстрирующий polling:

# import asyncio
# import random


# async def process_data(data):
#     print(f"Полученные данные: {data}")

#     # Может включать в себя любую другую логику, которую вы хотите выполнить с полученными данными,
#     # например, сохранение в базу данных, отправку уведомлений или обновление интерфейса пользователя.


# # Асинхронная функция для опроса сетевого устройства
# async def polling_network_device():
#     while True:
#         data = random.randint(0, 1000000)  #
#         await process_data(data)

#         # Здесь мы можем выполнить какие-то действия, 
#            # такие как отправку запроса к устройству и получение ответа

#         # Ожидание 5 секунд перед следующим опросом
#         await asyncio.sleep(5)


# async def main():
#     task = asyncio.create_task(polling_network_device())
#     await task


# asyncio.run(main())
# Код демонстрирует polling (опрос) в асинхронной манере, где асинхронная функция polling_network_device()
# циклически генерирует случайные данные, имитируя опрос сетевого устройства, и передает их в функцию process_data()
# для обработки. После генерации и обработки данных программа ожидает 5 секунд перед следующим циклом опроса.
# Это ожидание позволяет имитировать регулярный опрос устройства или сервиса с заданным интервалом времени.
# Такой подход часто используется для мониторинга состояний устройств или сервисов в реальном времени, когда
# необходимо регулярно получать и обновлять данные без создания излишней нагрузки на сеть или устройства.
####################################################
# Пример кода с прерыванием:

# Непросто продемонстрировать живой пример прерывания функции, поэтому продемонстрируем наглядный пример с
# имитацией прерывания каждые 3 секунды. На первый взгляд может быть непонятно, что конкретно происходит в этом коде, 
# но рекомендую его запустить и вдумчиво следить за ходом его работы. Далее в курсе мы ещё вернёмся к описанию всех
# используемых в этом коде методов и приёмов.

# Например, функция print_message() может выполняться беспрерывно, выполняя определённые действия каждую секунду, в
# то время как функция interrupt_handler() может проверять флаг interrupt_flag в течение всего времени. 

# В данном коде прерывание происходит каждые 3 секунды для наглядности демонстрации происходящего в коде, но на практике 
# прерывание должно срабатывать на определённое событие. О событиях и работе с ними мы будем говорить дальше в курсе.

# Важно понимать, что во время прерывания может быть вызвана любая другая функция из любой части вашего приложения.
# Это позволяет прерывать асинхронный код для выполнения функции в другом месте.
import asyncio


async def print_message():
    while True:
        print("Имитация работы функции")
        await asyncio.sleep(1)


async def interrupt_handler(interrupt_flag):
    while True:
        # Ждем установки флага
        await interrupt_flag.wait()
        print("Произошло прерывание! В этом месте может быть установлен любой обработчик")
        # Очищаем флаг для следующего использования
        interrupt_flag.clear()


async def main():
    interrupt_flag = asyncio.Event()
    asyncio.create_task(print_message())
    asyncio.create_task(interrupt_handler(interrupt_flag))

    while True:
        await asyncio.sleep(3)
        # Устанавливаем флаг для прерывания
        interrupt_flag.set()


asyncio.run(main())


# Функция print_message() имитирует рабочий процесс и выводит сообщение "Имитация работы функции" каждую секунду.

# Функция interrupt_handler Эта корутина ожидает события (флага прерывания), используя объект asyncio.Event() переданный
# как аргумент interrupt_flag. Корутина ждет, пока флаг будет установлен с помощью метода interrupt_flag.wait(). Как только
# флаг устанавливается, выводится сообщение "Произошло прерывание! В этом месте может быть установлен любой обработчик", после
# чего флаг сбрасывается методом interrupt_flag.clear() для следующего использования. Это позволяет корутине вновь перейти к 
# ожиданию установки флага.

# Функция main() создает флаг interrupt_flag с помощью asyncio.Event(). Затем создаются две задачи: первая выполняет функцию
# print_message(), а вторая — функцию interrupt_handler().
# В main() также содержится бесконечный цикл, в котором каждые три секунды устанавливается флаг прерывания с помощью interrupt_flag.set().
# Это событие активирует корутину interrupt_handler, которая реагирует на прерывание.

# Программа запускается с помощью asyncio.run(main()), что означает начало асинхронного выполнения в контексте нового цикла событий.
# Функция print_message() непрерывно выводит сообщения, пока функция interrupt_handler() реагирует на установленные каждые три секунды прерывания.